package com.why.config.proxy;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.util.EntityUtils;
import org.mitre.dsmiley.httpproxy.ProxyServlet;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.context.support.SpringBeanAutowiringSupport;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.stream.Collectors;


public class CustomProxyServlet extends ProxyServlet {

//    @Autowired
//    private ModuleRepository moduleRepository;
//
//    @Autowired
//    private ResourceRepository resourceRepository;
    private HttpClient proxyClient;
    private ServletConfig config;

    @Override
    public void init(ServletConfig config) throws ServletException{
        SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, config.getServletContext());
        this.config = config;
        String doLogStr = this.getConfigParam("log");
        if (doLogStr != null) {
            this.doLog = Boolean.parseBoolean(doLogStr);
        }

        String doForwardIPString = this.getConfigParam("forwardip");
        if (doForwardIPString != null) {
            this.doForwardIP = Boolean.parseBoolean(doForwardIPString);
        }

        String preserveHostString = this.getConfigParam("preserveHost");
        if (preserveHostString != null) {
            this.doPreserveHost = Boolean.parseBoolean(preserveHostString);
        }

        String preserveCookiesString = this.getConfigParam("preserveCookies");
        if (preserveCookiesString != null) {
            this.doPreserveCookies = Boolean.parseBoolean(preserveCookiesString);
        }

        String handleRedirectsString = this.getConfigParam("http.protocol.handle-redirects");
        if (handleRedirectsString != null) {
            this.doHandleRedirects = Boolean.parseBoolean(handleRedirectsString);
        }

        String connectTimeoutString = this.getConfigParam("http.socket.timeout");
        if (connectTimeoutString != null) {
            this.connectTimeout = Integer.parseInt(connectTimeoutString);
        }

        String readTimeoutString = this.getConfigParam("http.read.timeout");
        if (readTimeoutString != null) {
            this.readTimeout = Integer.parseInt(readTimeoutString);
        }

        String connectionRequestTimeout = this.getConfigParam("http.connectionrequest.timeout");
        if (connectionRequestTimeout != null) {
            this.connectionRequestTimeout = Integer.parseInt(connectionRequestTimeout);
        }

        String maxConnections = this.getConfigParam("http.maxConnections");
        if (maxConnections != null) {
            this.maxConnections = Integer.parseInt(maxConnections);
        }

        String useSystemPropertiesString = this.getConfigParam("useSystemProperties");
        if (useSystemPropertiesString != null) {
            this.useSystemProperties = Boolean.parseBoolean(useSystemPropertiesString);
        }

        this.initTarget();
        this.proxyClient = this.createHttpClient();
    }

    @Override
    public ServletConfig getServletConfig() {
        return this.config;
    }

    @Override
    protected void initTarget() throws ServletException {
        super.targetUri = "www.bai.com";
        try {
            super.targetUriObj = new URI(this.targetUri);
        } catch (Exception var2) {
            throw new ServletException("Trying to process targetUri init parameter: " + var2, var2);
        }

        super.targetHost = URIUtils.extractHost(this.targetUriObj);
    }

    @Override
    protected void service(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException {


        /// TODO: 2022/5/20  
//        String module = servletRequest.getHeader("module");
//        String uri = servletRequest.getHeader("uri");
//        Module moduleVa = moduleRepository.findOneByName(module);
//        if (StringUtils.isEmpty(uri)) {
//            servletResponse.setContentType("text/json;charset=utf-8");
//            servletResponse.getWriter().write(JSON.toJSONString(Result.fail("uri参数必传")));
//            return;
//        }
//        if (moduleVa != null && StringUtils.isEmpty(moduleVa.getValue())) {
//            servletResponse.setContentType("text/json;charset=utf-8");
//            servletResponse.getWriter().write(JSON.toJSONString(Result.fail("module参数有误")));
//            return;
//        }
//
//
//
//        List<String> roles = SecurityContextHolder.getContext().getAuthentication().getAuthorities().stream().map(Object::toString).collect(Collectors.toList());
//        if (!roles.contains("ADMIN")){
//            Resources resources = resourceRepository.findOneByRoles(roles,uri, ResourceEnum.OTHER.getName());
//            if (resources == null){
//                servletResponse.setContentType("text/json;charset=utf-8");
//                servletResponse.getWriter().write(JSON.toJSONString(Result.fail("该用户没有权限访问这个第三方接口！！")));
//                return;
//            }
//        }
//
//        servletRequest.setAttribute(ATTR_TARGET_URI, null);
//
//        assert moduleVa != null;
//        super.targetUri = "http://"+moduleVa.getValue()+uri;
//
//        URI url = null;
//        try {
//            url = new URI(targetUri);
//        } catch (URISyntaxException e) {
//
//            System.out.println("-----------"+targetUri);
//        }
//        servletRequest.setAttribute(ATTR_TARGET_HOST, null);
//        super.targetHost = URIUtils.extractHost(url);

        //------------------------------------------以上自定义信息------------------------------------------------------------------
        if (servletRequest.getAttribute(ATTR_TARGET_URI) == null) {
            servletRequest.setAttribute(ATTR_TARGET_URI, this.targetUri);
        }

        if (servletRequest.getAttribute(ATTR_TARGET_HOST) == null) {
            servletRequest.setAttribute(ATTR_TARGET_HOST, this.targetHost);
        }

        String method = servletRequest.getMethod();
        String proxyRequestUri = this.rewriteUrlFromRequest(servletRequest);
        Object proxyRequest;
        if (servletRequest.getHeader("Content-Length") == null && servletRequest.getHeader("Transfer-Encoding") == null) {
            proxyRequest = new BasicHttpRequest(method, proxyRequestUri);
        } else {
            proxyRequest = this.newProxyRequestWithEntity(method, proxyRequestUri, servletRequest);
        }

        this.copyRequestHeaders(servletRequest, (HttpRequest)proxyRequest);
        this.setXForwardedForHeader(servletRequest, (HttpRequest)proxyRequest);
        HttpResponse proxyResponse = null;

        try {
            proxyResponse = this.doExecute(servletRequest, servletResponse, (HttpRequest)proxyRequest);
            int statusCode = proxyResponse.getStatusLine().getStatusCode();
            servletResponse.setStatus(statusCode, proxyResponse.getStatusLine().getReasonPhrase());
            this.copyResponseHeaders(proxyResponse, servletRequest, servletResponse);
            if (statusCode == 304) {
                servletResponse.setIntHeader("Content-Length", 0);
            } else {
                this.copyResponseEntity(proxyResponse, servletResponse, (HttpRequest)proxyRequest, servletRequest);
            }
        } catch (Exception var11) {
            this.handleRequestException((HttpRequest)proxyRequest, var11);
        } finally {
            if (proxyResponse != null) {
                EntityUtils.consumeQuietly(proxyResponse.getEntity());
            }

        }
    }

    protected HttpResponse doExecute(HttpServletRequest servletRequest, HttpServletResponse servletResponse, HttpRequest proxyRequest) throws IOException {
        if (this.doLog) {
            this.log("proxy " + servletRequest.getMethod() + " uri: " + servletRequest.getRequestURI() + " -- " + proxyRequest.getRequestLine().getUri());
        }

        return this.proxyClient.execute(this.getTargetHost(servletRequest), proxyRequest);
    }


    private void setXForwardedForHeader(HttpServletRequest servletRequest, HttpRequest proxyRequest) {
        if (this.doForwardIP) {
            String forHeaderName = "X-Forwarded-For";
            String forHeader = servletRequest.getRemoteAddr();
            String existingForHeader = servletRequest.getHeader(forHeaderName);
            if (existingForHeader != null) {
                forHeader = existingForHeader + ", " + forHeader;
            }

            proxyRequest.setHeader(forHeaderName, forHeader);
            String protoHeaderName = "X-Forwarded-Proto";
            String protoHeader = servletRequest.getScheme();
            proxyRequest.setHeader(protoHeaderName, protoHeader);
        }

    }
}
